﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		CommentService.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 // 
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion

using System;
using System.Collections.Generic;
using System.Net.Mail;
using Dexter.Caching;
using Dexter.Core.EventArgs;
using Dexter.DataTransferObject;
using Dexter.Domain.Model;
using Dexter.Logger.Contracts;
using Dexter.Repository;

namespace Dexter.Services.Implementation {
	/// <summary>
	/// 	The implementatio of <see cref = "ICommentService" />.
	/// </summary>
	public class CommentService : ICommentService {
		readonly ICommentRepository commentRepository;
		readonly ILogger logger;
		readonly IPostRepository postRepository;
		readonly IConfigurationService configurationService;
		readonly ICacheProvider cacheProvider;

		/// <summary>
		/// Initializes a new instance of the <see cref="CommentService"/> class.
		/// </summary>
		/// <param name="commentRepository">The comment repository.</param>
		/// <param name="postRepository">The post repository.</param>
		/// <param name="logger">The logger.</param>
		/// <param name="configurationService">The configuration service.</param>
		public CommentService ( ICommentRepository commentRepository , IPostRepository postRepository , ILogger logger , IConfigurationService configurationService , ICacheProvider cacheProvider ) {
			this.logger = logger;
			this.cacheProvider = cacheProvider;
			this.configurationService = configurationService;
			this.commentRepository = commentRepository;
			this.postRepository = postRepository;
		}

		///<summary>
		///	Return a list approved comments, sorted by publish date.
		///</summary>
		///<param name = "numberOfItems">The number of items.</param>
		///<returns>
		///	Return a list of <see cref = "Comment" />.
		///	The return item could be null if there isn't items into the repository.
		///</returns>
		public IEnumerable <Comment> GetRecent ( int numberOfItems ) {
			var e = new CancelEventArgsWithOneParameter <int> ( numberOfItems );

			RecentCommentRetrieving.Raise ( this , e );

			if ( e.Cancel ) {
				return null;
			}

			IEnumerable <Comment> data = commentRepository.GetRecentCommentWithBasicItemProperties ( numberOfItems , false );

			RecentCommentRetrieved.Raise ( this , new GenericEventArgs <IEnumerable <Comment>> ( data ) );

			return data;
		}

		///<summary>
		///	Return a list approved comments, sorted by publish date.
		///</summary>
		///<param name = "numberOfItems">The number of items.</param>
		///<returns>
		///	Return a list of <see cref = "Comment" />.
		///	The return item could be null if there isn't items into the repository.
		///</returns>
		public IList<CommentDto> GetRecentCommentDto(int numberOfItems)
		{
			string key = string.Format ( "GetRecentCommentDto-{0}" , numberOfItems );

			var value = cacheProvider.Get<IList<CommentDto>>(key, CacheRegions.Tollerant)
				.Return ( o => o,
						  ( ) =>
						  {
							  var c =  commentRepository.GetRecentCommentWithBasicItemProperties ( numberOfItems , false ).ToDtos ( );

							  cacheProvider.Put ( key, c, TimeSpan.FromMinutes ( 30 ), CacheRegions.Tollerant, null );

							  return c;
						  } );

			return value;
		}

		/// <summary>
		/// 	Adds the comment for the specified post
		/// </summary>
		/// <param name = "message">The message of the comment.</param>
		/// <param name = "name">The name of the author of the comment.</param>
		/// <param name = "email">The email of the author of the comment.</param>
		/// <param name = "webSite">The web site of the author of the comment.</param>
		/// <param name = "itemId">The <see cref = "Item" /> id.</param>
		/// <param name = "parentId">The id of the parent <see cref = "Comment" /> .</param>
		public virtual void AddComment ( string message, string name, MailAddress email, Uri webSite, int itemId, int? parentId ) {
			var tupla = new Tuple <string , string , MailAddress , Uri , int , int?> ( message , name , email , webSite , itemId , parentId );
			var ea = new CancelEventArgsWithOneParameter <Tuple <string , string , MailAddress , Uri , int , int?>> ( tupla );

			CommentAdding.Raise ( this , ea );

			if ( ea.Cancel ) {
				return;
			}

			Comment parent = null;
			var item = postRepository.GetByKey ( itemId );

			if ( parentId.HasValue ) {
				parent = commentRepository.GetByKeyWithBasicItemProperties ( parentId.Value );
			}

			var comment = Comment.CreateNewComment ( item , webSite , email , message , name , parent );
			comment.Approved = configurationService.Configuration.CommentConfiguration.ModerationType == ModerationType.Post;

			commentRepository.Add ( comment );

			CommentAdded.Raise ( this , new GenericEventArgs <Comment> ( comment ) );
		}
		
		/// <summary>
		/// Saves the specified comment into the repository.
		/// </summary>
		/// <param name="item">The comment.</param>
		public void Save(Comment item)
		{
			int? parentId = null;
			if (item.Parent != null)
				parentId = item.Parent.Id;
			var tupla = new Tuple<string, string, MailAddress, Uri, int, int?>(item.Message, item.Name, item.Email, item.WebSite, item.Item.Id, parentId);
			var ea = new CancelEventArgsWithOneParameter<Tuple<string, string, MailAddress, Uri, int, int?>>(tupla);

			CommentAdding.Raise(this, ea);

			if (ea.Cancel)
			{
				return;
			}

			commentRepository.Save(item);

			CommentAdded.Raise(this, new GenericEventArgs<Comment>(item));
		}

		/// <summary>
		/// 	This event will raise before a new <see cref = "Comment" /> processed by the implementation of <see cref = "AddComment" />.
		/// </summary>
		public virtual event EventHandler<CancelEventArgsWithOneParameter<Tuple<string, string, MailAddress, Uri, int, int?>>> CommentAdding;

		/// <summary>
		/// 	This event will raise after a new <see cref = "Comment" /> processed by the implementation of <see cref = "AddComment" />.
		/// </summary>
		public virtual event EventHandler<GenericEventArgs<Comment>> CommentAdded;

		/// <summary>
		/// 	This event will raise before a list of <see cref = "Comment" /> will be retrieved by the implementation of <see cref = "GetRecent(int)" />.
		/// </summary>
		public virtual event EventHandler<CancelEventArgsWithOneParameter<int>> RecentCommentRetrieving;

		/// <summary>
		/// 	This event will raise after a list of <see cref = "Comment" /> will be retrieved by the implementation of <see cref = "GetRecent(int)" />.
		/// </summary>
		public virtual event EventHandler<GenericEventArgs<IEnumerable<Comment>>> RecentCommentRetrieved;
	}
}
